package cn.melonlib.cores.jpa.model.bean.adapter;

import cn.melonlib.cores.commons.comp.utils.HibernateQlParamsTool;
import cn.melonlib.cores.jpa.model.bean.PaginationQuery;
import cn.melonlib.cores.jpa.model.bean.Searcher;
import cn.melonlib.cores.jpa.model.bean.impl.PaginationList;

import javax.persistence.EntityManager;
import javax.persistence.Query;
import java.io.Serializable;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class PaginationSearcher<DATA> implements Searcher<PaginationList<DATA>, PaginationQuery> {
    @Override
    public PaginationList<DATA> search(PaginationQuery query, EntityManager entityManager) {
        Query q=entityManager.createQuery(query.getContent());
        HibernateQlParamsTool.setQueryParam(q,query.getParams());
        int start= (int) (query.getLimit()*(query.getPage()-1));
        q.setFirstResult(start);
        q.setMaxResults((int)query.getLimit());
        PaginationList<DATA> paginationList=new PaginationList<DATA>();
        paginationList.setTotal(this.countHqlRes(query.getContent(),query.getParams(),entityManager));
        paginationList.setPage(query.getPage());
        paginationList.setLimit(query.getLimit());
        paginationList.addAll(q.getResultList());
        return paginationList;
    }

    @Override
    public Class<PaginationQuery> registerType() {
        return PaginationQuery.class;
    }
    public static final Pattern cntRegex=Pattern.compile("^(select .+? )?(from .+)$");
    private int countHqlRes(String hql, List<? extends Serializable> params, EntityManager entityManager){
        Matcher m=cntRegex.matcher(hql);
        if(m.matches()){
            String cnthql="select count(*) "+ m.group(2);
            if(cnthql.indexOf("order by")!=-1){
                cnthql=cnthql.substring(0, cnthql.indexOf("order "));
            }
            Query query=entityManager.createQuery(cnthql);
            HibernateQlParamsTool.setQueryParam(query, params);
            return ((Long) query.getResultList().get(0)).intValue();
        }else{
            return 0;
        }
    }
}
